// ==UserScript==
// @name Facebook Profile Enhancer for Mafia Wars
// @namespace http://userscripts.org/users/118296
// @description Adds useful information and functions for Mafia Wars to the standard profile page of Facebook.
// @author Mewes Kochheim
// @contributor Metalpavel
// @betatester you-can-be-a-beta-tester-contact-me
// @include http://www.facebook.com/*
// @require http://userscripts.org/scripts/source/62727.user.js
// @version 0.1.3
// @history 0.1.3 bug fix for sucker punch and remove from mafia
// @history 0.1.2 added attack, punch and remove from mafia
// @history 0.1.1 bug fix for give help and loading animation fixed
// @history 0.1.0 Included script updater and money laundring
// @history 0.0.9 Added AJAX to Give help
// @history 0.0.5 Added AJAX to Join mafia
// @history 0.0.2 CSS bugs fixed
// @history 0.0.1 Initial release
// ==/UserScript==

////////////////////////////////////////////////////////////////////////////////
// Global
////////////////////////////////////////////////////////////////////////////////
ScriptUpdater.check(62326, '0.1.3');
var fbHelpCount = 0;
var fbHelpResponse = [];
var fbUserID = 0;
var fbPageChangeMarker = createMarker();
var fbOnLoadchecker = setInterval(function() { if($('content')) { clearInterval(fbOnLoadchecker); handleContentInsert(); } }, 100);
var fbMafiaHost = 'http://apps.facebook.com/inthemafia/remote/html_server.php?';
var fbJobList =
[
	['New York', fbMafiaHost + 'xw_controller=job&xw_action=give_help&job_city=1&target_id=', handleGiveHelpResponse],
	['Cuba', fbMafiaHost + 'xw_controller=job&xw_action=give_help&job_city=2&target_id=', handleGiveHelpResponse],
	['Moscow', fbMafiaHost + 'xw_controller=episode&xw_action=give_help_moscow_social&job_city=3&target_id=', handleGiveHelpResponse],
	['Moscow Boss Fight', fbMafiaHost + 'xw_controller=episode&xw_action=give_help_moscow_boss&job_city=3&target_id=', handleGiveHelpResponse],
	['Money Laundering', fbMafiaHost + 'xw_controller=launder&xw_action=give_help&job_city=1&job=69&target_id=', handleGiveHelpResponse]
];

////////////////////////////////////////////////////////////////////////////////
// Resources
////////////////////////////////////////////////////////////////////////////////

var mafiaIcon = '';
var loadIcon = '%3D%3D';

////////////////////////////////////////////////////////////////////////////////
// Event handler
////////////////////////////////////////////////////////////////////////////////

// @author sizzlemctwizzle
function handleContentInsert()
{
	var content = $('content');
	content.removeEventListener('DOMNodeInserted', handleContentInsert, false);
	if (!$(fbPageChangeMarker.id)) 
		setTimeout(handleFacebookLoad, 0);
	content.appendChild(fbPageChangeMarker);
	content.addEventListener('DOMNodeInserted', handleContentInsert, false);
}

// Obtains the user ID and start the HTTP request to Mafia Wars
function handleFacebookLoad()
{
	// Obtain user ID
	var shareLink = $$('.//a[contains(@href, "ajax/share_dialog.php")]')[0];
	if (shareLink == null) 
		return;
	/p\[\]=(\d+)/.exec(shareLink);
	fbUserID = RegExp.$1;
	
	// Add user ID
	$('profile_name').appendChild(document.createTextNode(' (ID: ' + fbUserID + ')'));
	
	// Request Mafia Wars profile
	getRequest(fbMafiaHost + 'xw_controller=stats&xw_action=view&user=' + fbUserID, handleProfileResponse);
}

// Creates all additional GUI components
function handleProfileResponse(_result, _attribute)
{
	var keyString = '';
	var profileActions = $$('.//div[@class="profile_actions"]')[0];
	var profileConnect = $('profile_connect_text');
	var profileIcon = $$('.//span[@class="profile_icon"]')[0];

	if (profileActions == null || _result.responseText == null || _result.responseText == '' || _result.responseText.lastIndexOf('This mafia member was not found') >= 0)
		return;

	// Parse player information and create information box
	/<div class=\"title\">\W+([\S ]+){0,1} {0,1}&#34;([\S ]+)&#34;, level ([0-9]+) (\S+)\W+<a href=/.exec(_result.responseText);
	var infoBox = createInfoBox(RegExp.$1, RegExp.$2, RegExp.$3, RegExp.$4);
	profileActions.parentNode.insertBefore(infoBox, profileActions.nextSibling);
		
	// Parse keys and create profile actions
	profileActions.appendChild(createProfileAction('View profile', 'actionViewProfile', fbMafiaHost + 'xw_controller=stats&xw_action=view&user=' + fbUserID));
	profileActions.appendChild(createProfileAction('Add to Hitlist', 'actionAddToHitlist', fbMafiaHost + 'xw_controller=hitlist&xw_action=set&target_id=' + fbUserID));
	profileActions.appendChild(createProfileAction('Declare War', 'actionDeclareWar', fbMafiaHost + 'xw_controller=war&xw_action=view&leader_id=' + fbUserID));

	if (!profileConnect && !profileIcon)
	{
		if (_result.responseText.lastIndexOf('xw_action=remove') < 0)
		{

		/fight&amp;xw_exp_sig=([a-z0-9]+)&amp;xw_time=([0-9]+)&amp;xw_action=attack&amp;.+?&amp;tmp=([a-z0-9]+)&amp;/.exec(_result.responseText);
	keyString = 'xw_exp_sig=' + RegExp.$1 + '&xw_time=' + RegExp.$2 + '&tmp=' + RegExp.$3;
	profileActions.appendChild(createProfileAction('Attack', 'actionAttack', fbMafiaHost + 'xw_controller=fight&xw_action=attack&' + keyString + '&opponent_id=' + fbUserID));
	
	/fight&amp;xw_exp_sig=([a-z0-9]+)&amp;xw_time=([0-9]+)&amp;xw_action=punch&amp;.+?&amp;tmp=([a-z0-9]+)&amp;/.exec(_result.responseText);
	keyString = 'xw_exp_sig=' + RegExp.$1 + '&xw_time=' + RegExp.$2 + '&tmp=' + RegExp.$3;
	profileActions.appendChild(createProfileAction('Sucker Punch', 'actionSuckerPunch', fbMafiaHost + 'xw_controller=fight&xw_action=punch&' + keyString + '&opponent_id=' + fbUserID));

			profileActions.appendChild(createProfileAction('Add to Mafia', 'actionAddToMafia', 'javascript:', function () { handleAddToMafiaClick(); }));
		}
		else
		{
	/fight&amp;xw_exp_sig=([a-z0-9]+)&amp;xw_time=([0-9]+)&amp;xw_action=punch&amp;.+?&amp;tmp=([a-z0-9]+)&amp;/.exec(_result.responseText);
	keyString = 'xw_exp_sig=' + RegExp.$1 + '&xw_time=' + RegExp.$2 + '&tmp=' + RegExp.$3;
	profileActions.appendChild(createProfileAction('Sucker Punch', 'actionSuckerPunch', fbMafiaHost + 'xw_controller=fight&xw_action=punch&' + keyString + '&opponent_id=' + fbUserID));

          		/group&amp;xw_exp_sig=([a-z0-9]+)&amp;xw_time=([0-9]+)&amp;xw_action=remove&amp;.+?&amp;tmp=([a-z0-9]+)&amp;/.exec(_result.responseText);
			keyString = 'xw_exp_sig=' + RegExp.$1 + '&xw_time=' + RegExp.$2 + '&tmp=' + RegExp.$3;
			profileActions.appendChild(createProfileAction('Remove from Mafia', 'actionRemoveFromMafia', 'javascript:', function () { handleRemoveFromMafiaClick(keyString); }));
		
        }
		profileActions.appendChild(createProfileAction('Give Help', 'actionGiveHelp', 'javascript:', function () { handleGiveHelpClick(); }));
		profileActions.appendChild(createProfileAction('Send Gift', 'actionSendGift', fbMafiaHost + 'xw_controller=gift&xw_action=view&target_id=' + fbUserID));
		profileActions.appendChild(createProfileAction('Promote', 'actionPromote', fbMafiaHost + 'xw_controller=group&xw_action=view&promote=yes&uid=' + fbUserID));
	}
}

function handleAddToMafiaResponse(_result, _attribute)
{
	/<td class=\"message_body\">([\S ]+)<\/td>/.exec(_result.responseText);
	
	// clean up result
	var message = cleanMessage(RegExp.$1);
	
	createPopupBox('Add to Mafia', [message]);
	$('actionAddToMafia').setAttribute('style', ''); 
	$('actionAddToMafiaWait').setAttribute('style', 'visibility:hidden;');
	$$('.//div[@class="profile_actions"]')[0].removeChild($('actionAddToMafia'));
	
//	var removeButton = createProfileAction('Remove from Mafia', 'javascript:', 'actionRemoveFromMafia', handleRemoveFromMafiaClick);
//	$$('.//div[@class="profile_actions"]')[0].replaceChild(null, $('actionAddToMafia'));
}

function handleRemoveFromMafiaResponse(_result, _attribute)
{
	/<td class=\"message_body\">([\S ]+)<\/td>/.exec(_result.responseText);
	
	// clean up result
	var message = cleanMessage(RegExp.$1);
	
	createPopupBox('Remove from Mafia', [message]);
	$('actionRemoveFromMafia').setAttribute('style', ''); 
	$('actionRemoveFromMafiaWait').setAttribute('style', 'visibility:hidden;');
	$$('.//div[@class="profile_actions"]')[0].removeChild($('actionRemoveFromMafia'));
	
//	var addButton = createProfileAction('Add to Mafia', 'javascript:', 'actionAddToMafia', handleAddToMafiaClick);
//	$$('.//div[@class="profile_actions"]')[0].replaceChild(addButton, $('actionRemoveFromMafia'));
}

function handleGiveHelpResponse(_result, _attribute)
{
	fbHelpCount++;
	
	if (_result != null)
	{
		// delete line breaks
		_result.responseText = _result.responseText.replace(/\n/g, '');
		
		// find message body
		/<td class=\"message_body\">(.+?)<\/td>/im.exec(_result.responseText);

		// clean up result
		var message = cleanMessage(RegExp.$1);

		var cityTitle = makeElement('b').appendChild(document.createTextNode(_attribute + ':'));
		fbHelpResponse.push(cityTitle);
		fbHelpResponse.push(makeElement('br'));
		fbHelpResponse.push(message);

		if (fbHelpCount == fbJobList.length) 
		{
			$('actionGiveHelp').setAttribute('style', ''); 
			$('actionGiveHelpWait').setAttribute('style', 'visibility:hidden;');
//			$$('.//div[@class="profile_actions"]')[0].removeChild($('actionGiveHelp'));
			createPopupBox('Give Help', fbHelpResponse);
		}
		else
		{
			fbHelpResponse.push(makeElement('br'));
			fbHelpResponse.push(makeElement('br'));
		}
	}
}

function handleAddToMafiaClick() 
{ 
	$('actionAddToMafia').setAttribute('style', 'color: #ffffff; background-color: #3B5998;'); 
	$('actionAddToMafiaWait').setAttribute('style', 'float: right; visibility: visible;'); 
	getRequest(fbMafiaHost + 'xw_controller=war&xw_action=add&friend_id=' + fbUserID, handleAddToMafiaResponse); 
}
function handleRemoveFromMafiaClick(_attribute) 
{
	$('actionRemoveFromMafia').setAttribute('style', 'color: #ffffff; background-color: #3B5998;'); 
	$('actionRemoveFromMafiaWait').setAttribute('style', 'float: right; visibility: visible;');
	getRequest(fbMafiaHost + 'xw_controller=group&xw_action=remove&xw_city=1&' + _attribute + '&target_id=' + fbUserID, handleRemoveFromMafiaResponse); 
}
function handleGiveHelpClick() 
{
	$('actionGiveHelp').setAttribute('style', 'color: #ffffff; background-color: #3B5998;'); 
	$('actionGiveHelpWait').setAttribute('style', 'float: right; visibility: visible;'); 
	
	fbHelpCount = 0;
	fbHelpResponse = [];
	
	for (var i in fbJobList) { getRequest(fbJobList[i][1] + fbUserID, fbJobList[i][2], fbJobList[i][0]); }
}

////////////////////////////////////////////////////////////////////////////////
// Functions to create GUI elements
////////////////////////////////////////////////////////////////////////////////

// Creates the box for the left column
function createInfoBox(_userTitle, _userName, _userLevel, _userType) 
{
	_userName = cleanString(_userName);
	
	var box = makeElement('div', null, {'class':'box basic_info_summary'});
	var boxTitle = makeElement('h5', box, {'class':'box_header UITitle UITitle_h5'}).appendChild(document.createTextNode('Mafia Wars Information'));
	var inside = makeElement('div', box, {'class':'inside'});
	var info = makeElement('dl', inside, {'class':'info'});
	
	if (_userTitle.length > 0) {
		makeElement('dt', info).appendChild(document.createTextNode('Title:'));
		makeElement('dd', info).appendChild(document.createTextNode(_userTitle));
	}
	
	makeElement('dt', info).appendChild(document.createTextNode('Name:'));
	makeElement('dd', info).appendChild(document.createTextNode(_userName));
	makeElement('dt', info).appendChild(document.createTextNode('Level:'));
	makeElement('dd', info).appendChild(document.createTextNode(_userLevel));
	makeElement('dt', info).appendChild(document.createTextNode('Type:'));
	makeElement('dd', info).appendChild(document.createTextNode(_userType));
	
	return box;
}

// Creates a profile action link
function createProfileAction(_text, _id, _href, _handler)
{
	var link = makeElement('a', null, {
		'id':_id, 
		'class':'profile_action actionspro_a', 
		'href':_href
	});
	
	if (_handler != null)	link.addEventListener('click', _handler, false);
		
	var icon = makeElement('img', link, {
		'src':mafiaIcon, 
		'style':'width: 11px; height:11px; margin-right: 3px; border: 0;'
	});
	
	link.appendChild(document.createTextNode(_text));
	
	var wait = makeElement('img', link, {
		'id':_id+'Wait',
		'src':loadIcon, 
		'style':'width: 16px; height: 11px; margin-right: 3px; border: 0; visibility: hidden;'
	});
	
	return link;
}

function createPopupBox(_title, _content)
{
	var popBorder1 = makeElement('div', $$('.//body')[0], {'id':'popupMafiaWars', 'class':'generic_dialog pop_dialog'});
	var popBorder2 = makeElement('div', popBorder1, {'class':'generic_dialog_popup', 'style':('top:' + (window.innerHeight / 2 + window.pageYOffset - 100) + 'px;')});
	var popContainer = makeElement('div', popBorder2, {'class':'pop_container_advanced'});
	var popContent = makeElement('div', popContainer, {'class':'pop_content'});
	var dialogTitle = makeElement('h2', popContent, {'class':'dialog_title'});
	var dialogTitleInner = makeElement('span', dialogTitle).appendChild(document.createTextNode(_title));
	var dialogContent = makeElement('div', popContent, {'class':'dialog_content'});
	var dialogBody = makeElement('div', dialogContent, {'class':'dialog_body'})
	
	if (_content != null) {
		for (var i in _content) {
			if (typeof _content[i] == 'object')
				dialogBody.appendChild(_content[i]);			
			else if (typeof _content[i] == 'string')
				dialogBody.appendChild(document.createTextNode(_content[i]));
		}
	}
	makeElement('br', dialogBody);
	makeElement('br', dialogBody);
	var dialogButtons = makeElement('div', dialogContent, {'class':'dialog_buttons'});
	var cancelButton = makeElement('input', dialogButtons, {'id':'cancelButton', 'class':'inputsubmit', 'type':'button', 'value':'OK'});					
	cancelButton.addEventListener('click', function() {$$('.//body')[0].removeChild($('popupMafiaWars'));}, false);	
}

// Creates a marker with a random ID
// @author sizzlemctwizzle
function createMarker()
{
	var s = '';
	for (i = 0; i <= 5; i++)
		s += String.fromCharCode(Math.floor(Math.random() * 75) + 48);
	return makeElement('div', null, {'id':'fbPageChangeMarker_' + s});
}

////////////////////////////////////////////////////////////////////////////////
// Utility functions
////////////////////////////////////////////////////////////////////////////////
 
// Get element by ID
function $(_id) 
{ 
	return document.getElementById(_id); 
}

// Get elements by XPath
function $$(_query, _element) { 
	var result = [];
	var element, elements = document.evaluate(_query, _element || document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
	while (element = elements.iterateNext()) 
		result.push(element);
	return result;
}

function makeElement(type, appendto, attributes) {
  var element = document.createElement(type);
  if (attributes != null) {
    for (var i in attributes) {
      element.setAttribute(i, attributes[i]);
    }
  }
  if (appendto != null) {
    appendto.appendChild(element);
  }
  return element;
}

function getRequest(_url, _function, _attribute) {
	GM_xmlhttpRequest({
		method: 'GET',
		url: _url,
		onload: function(_result) {
			if(_function)
				 _function(_result, _attribute);
		}
	});
}

// delete popups and remove html tags
function cleanMessage(_message) 
{
	return cleanString(_message.replace(/<div.+<\/div>/g, '').replace(/<(?:.|\s)*?>/g, ''));
}

// replace special html characters
function cleanString(_string)
{
	return _string.replace(/&quot;/g, '"').replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>');
}
